home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / reve / socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  16.8 KB  |  665 lines

  1. #ifdef REMOTE_PLAYER
  2. /*  @(#)socket.c 1.4 91/11/13
  3.  *
  4.  *  Various socket related routines used by reve for a networked game.
  5.  *  These routines are based on those found in the BSD talk program,
  6.  *  which is:
  7.  *
  8.  *  Copyright (c) 1983 Regents of the University of California.
  9.  *  All rights reserved.
  10.  *
  11.  *  Redistribution and use in source and binary forms are permitted
  12.  *  provided that: (1) source distributions retain this entire copyright
  13.  *  notice and comment, and (2) distributions including binaries display
  14.  *  the following acknowledgement:  ``This product includes software
  15.  *  developed by the University of California, Berkeley and its contributors''
  16.  *  in the documentation or other materials provided with the distribution
  17.  *  and in all advertising materials mentioning features or use of this
  18.  *  software. Neither the name of the University nor the names of its
  19.  *  contributors may be used to endorse or promote products derived
  20.  *  from this software without specific prior written permission.
  21.  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  */
  25.  
  26. #include "reve.h"
  27. #include <errno.h>
  28. #include "extern.h"
  29. #include <memory.h>
  30. #include <netdb.h>
  31. #include <signal.h>
  32. #include <setjmp.h>
  33. #include <sys/socket.h>
  34. #include <netinet/in.h>
  35. #include "ctl.h"
  36.  
  37. #ifdef X11
  38. #include <X11/Xos.h>
  39. #endif /*X11*/
  40.  
  41. extern int errno ;
  42.  
  43. static CTL_MSG msg ;
  44.  
  45. static struct sockaddr_in daemon_addr = { AF_INET } ;
  46. static struct sockaddr_in ctl_addr    = { AF_INET } ;
  47. static struct sockaddr_in my_addr     = { AF_INET } ;
  48.  
  49. static struct in_addr lmachine_addr ;    /* Inet address of this machine. */
  50. static struct in_addr rmachine_addr ;    /* Inet address of remote machine. */
  51. static struct itimerval itimer ;
  52. static struct timeval wait = { MSG_INTERVAL, 0 } ;
  53.  
  54. static u_short daemon_port ;             /* Port number of the Reve daemon. */
  55.  
  56. static char *current_state ;
  57.  
  58. static int ctl_sockt ;
  59. static int invitation_waiting ;
  60.  
  61. /*  The msg.id's for the invitations on the local and remote machines.
  62.  *  These are used to delete the invitations.
  63.  */
  64.  
  65. static int local_id ;
  66. static int remote_id ;
  67.  
  68. static jmp_buf invitebuf ;
  69.  
  70. static CTL_RESPONSE swapresponse P((CTL_RESPONSE)) ;
  71.  
  72. static int look_for_invite  P((CTL_RESPONSE *)) ;
  73.  
  74. static void announce_invite P(()) ;
  75. static void ctl_transact    P((struct in_addr, CTL_MSG, int, CTL_RESPONSE *)) ;
  76. static void disp_message    P(()) ;
  77. static void re_invite       P(()) ;
  78. static void send_delete     P(()) ;
  79.  
  80.  
  81. static void
  82. announce_invite()     /* Transmit the invitation and process the response */
  83. {
  84.   CTL_RESPONSE response ;
  85.  
  86.   current_state = "Trying to connect to your opponent's reve daemon" ;
  87.  
  88.   ctl_transact(rmachine_addr, msg, ANNOUNCE, &response) ;
  89.   remote_id = response.id_num ;
  90.  
  91.   if (response.answer != SUCCESS)
  92.     {
  93.       switch (response.answer)
  94.         {
  95.           case NOT_HERE          : message(PANEL_MES,
  96.                                      "Your opponent is not logged on") ;
  97.                                    break ;
  98.  
  99.           case MACHINE_UNKNOWN   : message(PANEL_MES,
  100.                                      "Remote machine does not recognize us") ;
  101.                                    break ;
  102.  
  103.           case UNKNOWN_REQUEST   : message(PANEL_MES,
  104.                                      "Remote machine can not handle reve") ;
  105.                                    break ;
  106.  
  107.           case FAILED            : message(PANEL_MES,
  108.                                      "Remote machine is too confused") ;
  109.                                    break ;
  110.  
  111.           case PERMISSION_DENIED : message(PANEL_MES,
  112.                                      "Your opponent is refusing messages") ;
  113.         }
  114.       if (invitation_waiting) send_delete() ;
  115.       destroy_reve() ;
  116.     }
  117.  
  118. /* Leave the actual invitation on my reve daemon. */
  119.                  
  120.   ctl_transact(lmachine_addr, msg, LEAVE_INVITE, &response) ;
  121.   local_id = response.id_num ;
  122. }
  123.  
  124.  
  125. /*  SOCKDGRAM is unreliable, so we must repeat messages if we have
  126.  *  not received an acknowledgement within a reasonable amount of time
  127.  */
  128.  
  129. static void
  130. ctl_transact(target, msg, type, response)
  131. struct in_addr target ;
  132. CTL_MSG msg ;
  133. int type ;
  134. CTL_RESPONSE *response ;
  135. {
  136.   struct sockaddr junk ;
  137.   struct timeval wait ;
  138.   int cc, junk_size, nready ;
  139.  
  140. #ifdef NO_43SELECT
  141.   int ctl_mask, read_mask ;
  142. #else
  143.   fd_set ctl_mask, read_mask ;
  144. #endif /*NO_43SELECT*/
  145.  
  146.   wait.tv_sec  = CTL_WAIT ;
  147.   wait.tv_usec = 0 ;
  148.  
  149.   msg.type     = type ;
  150.  
  151.   daemon_addr.sin_addr = target ;
  152.   daemon_addr.sin_port = daemon_port ;
  153.  
  154. #ifdef NO_43SELECT
  155.   ctl_mask = 1 << ctl_sockt ;
  156. #else
  157.   FD_ZERO(&ctl_mask) ;
  158.   FD_SET(ctl_sockt, &ctl_mask) ;
  159. #endif /*NO_43SELECT*/
  160.  
  161. /* Keep sending the message until a response of the right type is obtained. */
  162.  
  163.   do
  164.     {
  165.       do
  166.         {
  167.           cc = sendto(ctl_sockt, (char *) &msg, sizeof(CTL_MSG), 0,
  168.                       &daemon_addr, sizeof(daemon_addr)) ;
  169.  
  170.           if (cc != sizeof(CTL_MSG))
  171.             {
  172.               if (errno == EINTR) continue ;  /* Returning from an interrupt. */
  173.               else perror("Error on write to reve daemon") ;
  174.             }    
  175.  
  176.           read_mask = ctl_mask ;
  177.  
  178. #ifdef NO_43SELECT
  179.           while ((nready = select(32, &read_mask, 0, 0, &wait)) < 0)
  180. #else
  181.           while ((nready = select(FD_SETSIZE, &read_mask,
  182.                                   (fd_set *) 0, (fd_set *) 0, &wait)) < 0)
  183. #endif /*NO_43SELECT*/
  184.             {
  185.               if (errno == EINTR) continue ;  /* Returning from an interrupt. */
  186.               else perror("Error on waiting for response from daemon") ;
  187.             }    
  188.         }
  189.       while (nready == 0) ;
  190.  
  191. /*  Keep reading while there are queued messages (this is not necessary,
  192.  *  it just saves extra request/acknowledgements being sent).
  193.  */
  194.  
  195.       do
  196.         {
  197.           junk_size = sizeof(junk) ;
  198.           cc = recvfrom(ctl_sockt, (char *) response,
  199.                         sizeof(CTL_RESPONSE), 0, &junk, &junk_size) ;
  200.           if (cc < 0)
  201.             {
  202.               if (errno == EINTR) continue;
  203.               perror("Error on read from reve daemon") ;
  204.             }
  205.  
  206.           read_mask = ctl_mask ;
  207.  
  208. /* An immediate poll. */
  209.  
  210.           timerclear(&wait) ;
  211. #ifdef NO_43SELECT
  212.           nready = select(32, &read_mask, 0, 0, &wait) ;
  213. #else
  214.           nready = select(FD_SETSIZE, &read_mask,
  215.                           (fd_set *) 0, (fd_set *) 0, &wait) ;
  216. #endif /*NO_43SELECT*/
  217.         }
  218.       while (nready > 0 && response->type != type) ;
  219.     }
  220.   while (response->type != type) ;
  221. }
  222.  
  223.  
  224. static SIGRET
  225. disp_msg()
  226. {
  227.   message(PANEL_MES, current_state) ;
  228. }
  229.  
  230.  
  231. void
  232. end_msgs()
  233. {
  234.   SIGNAL(SIGALRM, SIG_IGN) ;
  235.   timerclear(&itimer.it_value) ;
  236.   timerclear(&itimer.it_interval) ;
  237.   setitimer(ITIMER_REAL, &itimer, (struct timerval *) 0) ;
  238. }
  239.  
  240.  
  241. void
  242. get_addrs(luserhost, ruserhost)
  243. char *luserhost, *ruserhost ;
  244. {
  245.   struct hostent *hp ;
  246.   struct servent *sp ;
  247.   char *ptr, luser[MAXLINE], lhost[MAXLINE], ruser[MAXLINE], rhost[MAXLINE] ;
  248.  
  249.   ptr = index(luserhost, '@') ;
  250.   STRNCPY(luser, luserhost, ptr - luserhost) ;
  251.   luser[ptr - luserhost] = '\0' ;
  252.   STRCPY(lhost, ptr+1) ;
  253.  
  254.   if ((ptr = index(ruserhost, '@')) == NULL)
  255.     {
  256.       STRCPY(ruser, ruserhost) ;
  257.       STRCPY(rhost, lhost) ;        /* No hostname; assume local host. */
  258.     }
  259.   else
  260.     {
  261.       STRNCPY(ruser, ruserhost, ptr - ruserhost) ;
  262.       ruser[ptr - ruserhost] = '\0' ;
  263.       STRCPY(rhost, ptr+1) ;
  264.     }
  265.  
  266.   hp = gethostbyname(lhost) ;       /* Look up address of local host. */
  267.  
  268.   if (hp == (struct hostent *) 0)
  269.     {
  270.       PRINTF("Local host (%s) doesn't exist.\n", lhost) ;
  271.       exit(1) ;
  272.     }
  273.  
  274.   if (hp->h_addrtype != AF_INET)
  275.     {
  276.       PRINTF("Protocal mix up with local machine address\n") ;
  277.       exit(-1) ;
  278.     }
  279.  
  280.   MEMCPY((char *) &lmachine_addr, hp->h_addr, hp->h_length) ;
  281.  
  282. /* If s/he is on the same machine, then simply copy. */
  283.  
  284.   if (memcmp((char *) rhost, (char *) lhost, sizeof(lhost)) == 0)
  285.     MEMCPY((char *) &rmachine_addr, (char *) &lmachine_addr,
  286.            sizeof(rmachine_addr)) ;
  287.   else
  288.     {
  289.       if ((rmachine_addr.s_addr = inet_addr(rhost)) == -1)
  290.         {
  291.  
  292. /* Look up the address of the recipient's machine. */
  293.  
  294.           if ((hp = gethostbyname(rhost)) == (struct hostent *) 0)
  295.             {
  296.               PRINTF("%s is an unknown host\n", rhost) ;
  297.               exit(1) ;
  298.             }
  299.  
  300.           if (hp->h_addrtype != AF_INET)
  301.             {
  302.               PRINTF("Protocol mix up with remote machine address\n") ;
  303.               exit(1) ;
  304.             }
  305.           MEMCPY((char *) &rmachine_addr, hp->h_addr, hp->h_length) ;
  306.         }
  307.     }    
  308.  
  309. /* Find the daemon portal. */
  310.  
  311.   if ((sp = getservbyname("reve", "udp")) == NULL)
  312.     {
  313.       perror("This machine doesn't support a tcp reve daemon") ;
  314.       exit(1) ;
  315.     }
  316.  
  317.   if (strcmp(sp->s_proto, "udp") != 0)
  318.     {
  319.       PRINTF("Protocol mix up with reve daemon\n") ;
  320.       exit(1) ;
  321.     }
  322.   daemon_port = sp->s_port ;
  323.  
  324. /* Load these useful values into the standard message header */
  325.  
  326.   msg.id_num = 0 ;
  327.   msg.dtype  = dtype ;
  328.  
  329.   STRNCPY(msg.l_name, luser, NAME_SIZE) ;
  330.   msg.l_name[NAME_SIZE - 1] = '\0' ;
  331.  
  332.   STRNCPY(msg.r_name, ruser, NAME_SIZE) ;
  333.   msg.r_name[NAME_SIZE - 1] = '\0' ;
  334.  
  335.   STRNCPY(msg.r_tty, "", TTY_SIZE) ;     /* Possibly allow tty name later. */
  336.   msg.r_tty[TTY_SIZE - 1] = '\0' ;
  337. }
  338.  
  339.  
  340. /*  There wasn't an invitation waiting, so send a request containing
  341.  *  our socket address to the remote reve daemon so it can invite them.
  342.  */
  343.  
  344. void
  345. invite_remote()
  346. {
  347.   int nfd, read_mask, template, new_sockt ;
  348.   struct itimerval itimer ;
  349.   CTL_RESPONSE response ;
  350.  
  351.   itimer.it_value.tv_sec  = RING_WAIT ;
  352.   itimer.it_value.tv_usec = 0 ;
  353.   itimer.it_interval      = itimer.it_value ;
  354.  
  355.   if (listen(socketfd, 5) != 0)
  356.     perror("Error on attempt to listen for caller") ;
  357.  
  358.   msg.addr = my_addr ;
  359.   msg.id_num = -1 ;               /* An impossible id_num. */
  360.  
  361.   invitation_waiting = 1 ;
  362.  
  363.   announce_invite() ;
  364.  
  365. /*  Shut off the automatic messages for a while,
  366.  *  so we can use the interupt timer to resend the invitation.
  367.  */
  368.  
  369.   end_msgs() ;
  370.   setitimer(ITIMER_REAL, &itimer, (struct itimerval *) 0) ;
  371.   message(PANEL_MES, "Waiting for your opponent to respond") ;
  372.   SIGNAL(SIGALRM, re_invite) ;
  373.   SETJMP(invitebuf) ;
  374.  
  375.   while ((new_sockt = accept(socketfd, 0, 0)) < 0)
  376.     {
  377.       if (errno != EINTR)
  378.         perror("Unable to connect with your opponent") ;
  379.       else 
  380.         continue ;      /* We just returned from a interupt, keep trying. */
  381.     }    
  382.  
  383.   CLOSE(socketfd) ;
  384.   socketfd = new_sockt ;
  385.  
  386. /* Have the daemons delete the invitations now that we have connected. */
  387.  
  388.   current_state = "Waiting for your opponent to respond" ;
  389.   start_msgs() ;
  390.  
  391.   msg.id_num = local_id ;
  392.   ctl_transact(lmachine_addr, msg, DELETE, &response) ;
  393.   msg.id_num = remote_id ;
  394.   ctl_transact(rmachine_addr, msg, DELETE, &response) ;
  395.   invitation_waiting = 0 ;
  396. }
  397.  
  398.  
  399. int
  400. is_local()      /* See if the local daemon has a invitation for us. */
  401. {
  402.   CTL_RESPONSE response ;
  403.  
  404. /* The rest of msg was set up in get_names. */
  405.  
  406.   msg.ctl_addr = ctl_addr ;
  407.  
  408.   if (!look_for_invite(&response))
  409.     return(0) ;                      /* We must be initiating a connection. */
  410.  
  411. /*  There was an invitation waiting for us,
  412.  *  so connect with the other (hopefully waiting) party
  413.  */
  414.  
  415.   current_state = "Waiting to connect with caller" ;
  416.  
  417.   response = swapresponse(response) ;
  418.   while (connect(socketfd, &response.addr, sizeof(response.addr)) != 0)
  419.     {
  420.       if (errno == ECONNREFUSED)
  421.         {
  422.  
  423. /*  The caller gave up, but his invitation somehow
  424.  *  was not cleared. Clear it and initiate an
  425.  *  invitation. (We know there are no newer invitations,
  426.  *  the reved works LIFO.)
  427.  */
  428.  
  429.           ctl_transact(rmachine_addr, msg, DELETE, &response) ;
  430.           CLOSE(socketfd) ;
  431.           open_socket() ;
  432.           return(0) ;
  433.         }
  434.       else if (errno == EINTR)
  435.         continue ;    /* We have returned from an interupt handler. */
  436.       else
  437.         perror("Unable to connect with initiator") ;
  438.     }
  439.   return(1) ;
  440. }
  441.  
  442.  
  443. static int
  444. look_for_invite(response)      /* Look for an invitation on 'machine'. */
  445. CTL_RESPONSE *response ;
  446. {
  447.   struct in_addr machine_addr ;
  448.  
  449.   current_state = "Checking for invitation on caller's machine" ;
  450.  
  451.   ctl_transact(rmachine_addr, msg, LOOK_UP, response) ;
  452.  
  453. /* The switch is for possible later options, such as multiple invitations. */
  454.  
  455.   switch (response->answer)
  456.     {
  457.       case SUCCESS : msg.id_num = response->id_num ;
  458.                      dtype = (response->dtype == XBLACK) ? XWHITE : XBLACK ;
  459.                      return(1) ;
  460.  
  461.       default      : /* There wasn't an invitation waiting for us. */
  462.                      return(0) ;
  463.     }
  464. }
  465.  
  466.  
  467. void
  468. open_ctl()        /* Open the ctl socket. */
  469. {
  470.   int length ;
  471.  
  472.   ctl_addr.sin_port = 0 ;
  473.   ctl_addr.sin_addr = lmachine_addr ;
  474.  
  475.   if ((ctl_sockt = socket(AF_INET, SOCK_DGRAM, 0, 0)) <= 0)
  476.     perror("Bad socket") ;
  477.  
  478.   if (bind(ctl_sockt, &ctl_addr, sizeof(ctl_addr), 0) != 0)
  479.     perror("Couldn't bind to control socket") ;
  480.  
  481.   length = sizeof(ctl_addr) ;
  482.   if (getsockname(ctl_sockt, &ctl_addr, &length) == -1)
  483.     perror("Bad address for ctl socket") ;
  484.  
  485.   current_state = "No connection yet" ;
  486. }
  487.  
  488.  
  489. void
  490. open_socket()
  491. {
  492.   int length ;
  493.  
  494.   my_addr.sin_addr = lmachine_addr ;
  495.   my_addr.sin_port = 0 ;
  496.  
  497.   if ((socketfd = socket(AF_INET, SOCK_STREAM, 0, 0)) <= 0)
  498.     perror("Bad socket") ;
  499.  
  500.   if (bind(socketfd, &my_addr, sizeof(my_addr)) != 0)
  501.     perror("Binding local socket") ;
  502.  
  503.   length = sizeof(my_addr);
  504.   if (getsockname(socketfd, &my_addr, &length) == -1)
  505.     perror("Bad address for socket") ;
  506. }
  507.  
  508.  
  509. void
  510. read_from_sock(socketfd)       /* Read move from remote user@host. */
  511. int socketfd ;
  512. {
  513.   struct reve_out out ;
  514.   int sout ;
  515.  
  516.   sout = sizeof(struct reve_out) ;
  517.   if (read(socketfd, (char *) &out, sout) <= 0)
  518.     {
  519.       FPRINTF(stderr, "%s: Connection to opponent closed. Exiting.\n",
  520.               progname) ;
  521.       destroy_reve() ;
  522.     }
  523.   else
  524.     {
  525.       if (out.type == M_MOVE)
  526.         {
  527.           set_cursor(CANVASCUR) ;
  528.           move = out.move ;
  529.           note = out.note ;
  530.           opponent_move(next_player) ;
  531.         }
  532.     }
  533. }
  534.  
  535.  
  536. static void
  537. re_invite()      /* Routine called on interupt to re-invite the callee. */
  538. {
  539.   message(PANEL_MES, "Ringing your opponent again") ;
  540.   msg.id_num = remote_id + 1 ;       /* Force a re-announce. */
  541.   announce_invite() ;
  542.   longjmp(invitebuf, 1) ;
  543. }
  544.  
  545.  
  546. static void
  547. send_delete()    /* Tell the daemon to remove your invitation. */
  548. {
  549.   msg.type = DELETE;
  550.  
  551. /*  This is just a extra clean up, so just send it and don't wait
  552.  *  for an answer.
  553.  */
  554.  
  555.   msg.id_num = remote_id ;
  556.   daemon_addr.sin_addr = rmachine_addr ;
  557.   if (sendto(ctl_sockt, &msg, sizeof(CTL_MSG), 0, &daemon_addr,
  558.              sizeof(daemon_addr)) != sizeof(CTL_MSG))
  559.     perror("send_delete remote") ;
  560.  
  561.   msg.id_num = local_id ;
  562.   daemon_addr.sin_addr = lmachine_addr ;
  563.   if (sendto(ctl_sockt, &msg, sizeof(CTL_MSG), 0, &daemon_addr,
  564.              sizeof(daemon_addr)) != sizeof(CTL_MSG))
  565.     perror("send_delete local") ;
  566. }
  567.  
  568.  
  569. void
  570. start_msgs()
  571. {
  572.   message(PANEL_MES, current_state) ;
  573.   SIGNAL(SIGALRM, disp_msg) ;
  574.   itimer.it_value = itimer.it_interval = wait ;
  575.   setitimer(ITIMER_REAL, &itimer, (struct timerval *) 0) ;
  576. }
  577.  
  578.  
  579. /* Heuristic to detect if need to reshuffle CTL_RESPONSE structure. */
  580.  
  581. #if defined(mc68000) || defined(hpux)
  582. struct ctl_response_runrise {
  583.   char type ;
  584.   char answer ;
  585.   short junk ;
  586.   int id_num ;
  587.   struct sockaddr_in addr ;
  588. } ;
  589.  
  590.  
  591. static CTL_RESPONSE
  592. swapresponse(rsp)
  593. CTL_RESPONSE rsp ;
  594. {
  595.   struct ctl_response_runrise swaprsp ;
  596.  
  597.   if (rsp.addr.sin_family != AF_INET)
  598.     {
  599.       MEMCPY(&swaprsp, &rsp, sizeof(CTL_RESPONSE)) ;
  600.       if (swaprsp.addr.sin_family == AF_INET)
  601.         {
  602.           rsp.addr = swaprsp.addr ;
  603.           rsp.type = swaprsp.type ;
  604.           rsp.answer = swaprsp.answer ;
  605.           rsp.id_num = swaprsp.id_num ;
  606.         }
  607.     }
  608.   return(rsp) ;
  609. }
  610. #endif
  611.  
  612.  
  613. #ifdef sparc
  614. struct ctl_response_sun3 {
  615.   char type ;
  616.   char answer ;
  617.   unsigned short id_num2 ;
  618.   unsigned short id_num1 ;
  619.   short sin_family ;
  620.   short sin_port ;
  621.   short sin_addr2 ;
  622.   short sin_addr1 ;
  623. } ;
  624.  
  625.  
  626. static CTL_RESPONSE
  627. swapresponse(rsp)
  628. CTL_RESPONSE rsp ;
  629. {
  630.   struct ctl_response_sun3 swaprsp ;
  631.  
  632.   if (rsp.addr.sin_family != AF_INET)
  633.     {
  634.       MEMCPY(&swaprsp, &rsp, sizeof(struct ctl_response_sun3)) ;
  635.       if (swaprsp.sin_family == AF_INET)
  636.         {
  637.           rsp.type = swaprsp.type ;
  638.           rsp.answer = swaprsp.answer ;
  639.           rsp.id_num = swaprsp.id_num1 | (swaprsp.id_num2 << 16) ;
  640.           rsp.addr.sin_family = swaprsp.sin_family ;
  641.           rsp.addr.sin_port = swaprsp.sin_port ;
  642.           rsp.addr.sin_addr.s_addr = (swaprsp.sin_addr2 << 16) |
  643.                                       swaprsp.sin_addr1 ;
  644.         }
  645.     }
  646.   return(rsp) ;
  647. }
  648. #endif
  649.  
  650.  
  651. void
  652. write_to_sock(socketfd, move)       /* Write move to remote user@host. */
  653. int socketfd, move ;
  654. {
  655.   struct reve_out out ;
  656.  
  657.   out.type    = M_MOVE ;
  658.   out.move    = move ;
  659.   out.note    = 0 ;
  660.   out.depth   = 0 ;
  661.   processing  = TRUE ;
  662.   WRITE(socketfd, (char *) &out, sizeof(struct reve_out)) ;
  663. }
  664. #endif /* REMOTE_PLAYER */
  665.